In version 7.x.y, x should change only when some documented user-visible aspect of Xconq changes, whether in the interface or kernel. In particular, any additions to GDL, such as a new table or property, require a new x version. y is reserved for bug-fix releases, which can include the implementation of features that were documented but not working correctly or completely.
The macro VERSION
should also include a date in parentheses,
formatted in "military style", as in "8 Jul 1995". Be sure to set
the date to some approximation of the date of your most recent change to
the sources.
The Xconq sources adhere to a number of coding standards that you should follow also. While everyone has their individual style, it is important to the code's maintenance that the existing style be preserved.
You should allocate by using xmalloc
. This routine checks for
allocation validity and gives a useful error message if allocation
fails, it zeroes the block so you can count on the newly allocated space
being in a known state, and it collects statistical data, which is
important to optimization.
There is one exception to this allocation rule, which is that you may
use malloc
if you intend to free the memory shortly. An example
would be temporary working space needed by an interface. However, you
must then check the return result from malloc
yourself and handle
failures appropriately; remember that players can easily ask for very
large games, so it's quite possible that any given call to malloc
will be unable to allocate the desired memory.
Always generate a random number by using xrandom
. This is a
generator of known and consistent properties across all systems that
Xconq runs on. Consistency is especially critical for ensuring
that networked games stay in sync.
Indent by 4, with tabs at 8. This is effectively what you get in Emacs
if you set c-indent-level
to 4. System-specific interfaces need
not adhere to this rule..
This chapter would not be complete without some discussion of the traps awaiting the unwary hacker. The Absolute Number One Hazard in hacking Xconq is to introduce code that does not work for all game designs. It is all too easy to assume that, for instance, unit speeds are always less than 20, or airbases can only be built by infantry, or that worlds are always randomly-generated. These sorts of assumptions have caused no end of problems. Code should test preconditions, especially for dynamically-allocated game-specified objects, and it should be tested using the various test scripts in the test directory.
The number two pitfall is to not account for all the possible interfaces. Not all interfaces have a single "current unit" or map window, and some communicate with multiple players or over a network connection.
You should not assume that your hack is generally valid until you have
tested it against everything in the library and test directories. The
test
directory contains scripts that will be useful for this, at
least to Unix hackers. See the README
in that directory for more
information.
Another pitfall is to be sloppy about performance. An algorithm that
works fine in a small world with two sides and 50 units may be painfully
slow in a large game. Or, the algorithm may allocate too much working
space and wind up exhausting memory (this has often happened). You
should familiarize yourself with the algorithms already used in
Xconq, since they have already been debugged and tuned, and many
have been written as generically useful code (see the area-scanning
functions in world.c
for instance).
If your new feature is expensive, then define a global and compute its
value only once, either at the start of the game or when it becomes
relevant. Such a global should be named any_<feature>
.
Similarly, complicated tests on unit types or sides should be calculated once and cached in a dynamically-allocated array.
You may have noticed that Xconq sources have been liberally sprinkled with debugging code, and you may desire to add some yourself. In this modern age of computing, powerful source-level debuggers are widely available, so there is no good reason to add debugging code to do a job that would be better done by the debugger. Xconq debugging output is generally designed to be useful for understanding average behavior, changes over time, and "high-level transients" such as thrashing in plan or task execution; information that is difficult to collect using only a debugger. When adding new debug output, you should keep this principle in mind. Also, be aware that some of the automated testing scripts enable debug output, so if you add something that is uselessly voluminous, testing output may fill your disk prematurely!
This is where I justify what I've done, and not done.
Please note that although Xconq has considerable power, its design was expressly limited to a particular class of two-dimensional board-like strategy games, and that playability is emphasized over generality. For instance, I avoided the temptation to include a general-purpose language, since it opens up many difficult issues and makes it much harder for game designers to produce a desired game (after all, if game designers wanted to use a general-purpose programming language, they could just write C code!). Similarly, full 3D, realtime maneuvering, continuous terrain, and other such goodies must await the truly ultimate game system.
The real problem with a general-purpose language is that although everything is possible, nothing is easy. Many "adventure game writing systems" have fallen into this trap; they end up being poor reimplementations of standard programming languages, and the sole support for adventure gaming amounts to a small program skeleton and a few library functions. It would have been easier just to start with a pre-existing language and just write the skeleton and libraries!
Xconq, on the other hand, provides extensive optimized support for random game setup, large numbers of units, game save/restore, computer opponents, and many other facets of a game. Game designers don't have to deal with the subleties of fractal terrain synthesis, or the ordering of terrain effects on units, or how to tell the computer opponents that airbases are sometimes good for refueling but never any good for transportation, or the myriad of other details that are wired into Xconq. In fact, a complete working game can be set up with less than a half-page of GDL.
Even so, the current Xconq design allows for several layers of extensibility, as was described earlier in this chapter.
There are also several major areas in which Xconq could be improved.
Tables should be supplemented with general formulae, although such formulae will complicate AIs' analyses considerably, since tables are much easier to scan. Formula-based game definition would work much better with AIs that are coded specifically for the game and compiled in; this is more-or-less possible now, but there is not yet a good way to keep AIs from being used in games where they would be inappropriate (it might be amusing to have a panzer general AI attempting to play Gettysburg, but the coding would have to be careful not to try to index nonexistent unit types).
Currently everything is based on a single area of a single world. This could be extended to multiple areas in the world, perhaps at different scales, as well as to multiple worlds. The coding implications are severe, since much of the code mentions x,y alone, with the area implicit. One intermediate solution is to have one area be "active" and shift areas as needed (multiple-level dungeon games work this way).
However, even with its limitations, Xconq has provided, and will continue to provide, many years of enjoyable playing, designing, and hacking. Go to it!